using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using FireStarter.Base;
using FireStarter.CodeGeneration;
using FireStarterModeller.BO;
using Habanero.Util;

namespace FireStarter.CodeGeneration.Generator
{
    /// <summary>
    /// Provides a master abstract class for expressions that make up
    /// a full template to be generated
    /// </summary>
    public abstract class TemplateExpression
    {
        public const string DELETION_MARKER = "@#DELETEME#@";

        /// <summary>
        /// Gets and sets the next expression to follow this one
        /// </summary>
        public TemplateExpression Next { get; set; }

        /// <summary>
        /// Generates a final template from the components held in a
        /// linked list of template expressions
        /// </summary>
        /// <param name="mapper">The mapper that indicates which strategies
        /// correspond to each element type</param>
        /// <param name="modelElement">The model element for which the template
        /// is being generated</param>
        public string Generate(IModelStrategyMapper mapper, IModelElement modelElement)
        {
            string result = GenerateNext(mapper, modelElement);
            return StripOutExtraNewlines(result);
        }

        /// <summary>
        /// Gets the generated text for this particular expression and for
        /// all the expressions that are linked to it through the Next property.
        /// </summary>
        private string GenerateNext(IModelStrategyMapper mapper, IModelElement modelElement)
        {
            string result = GenerateOne(mapper, modelElement);
            if (!(this is LiteralExpression) && String.IsNullOrEmpty(result))
            {
                result = DELETION_MARKER;
            }

            if (Next != null)
            {
                result += Next.GenerateNext(mapper, modelElement);
            }
            return result;
        }

        /// <summary>
        /// Generates the text for this particular expression
        /// </summary>
        /// <param name="mapper">The mapper that indicates which strategies
        /// correspond to each element type</param>
        /// <param name="modelElement">The model element for which the template
        /// is being generated</param>
        /// <returns>Returns the generated text</returns>
        protected abstract string GenerateOne(IModelStrategyMapper mapper, IModelElement modelElement);

        /// <summary>
        /// Provides functionality to delete extra lines in the template created
        /// by comments and actions that produce empty strings.
        /// Searches for deletion markers in the generated template.
        /// Deletes them, but where they are part of a line with only whitespace,
        /// that whole line is effectively deleted.
        /// </summary>
        private static string StripOutExtraNewlines(string result)
        {
            StringBuilder stringBuilder = new StringBuilder();

            string[] stringParts = result.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
            for (int stringNum = 0; stringNum < stringParts.Length; stringNum++)
            {
                string part = stringParts[stringNum];
                if (part.Contains(DELETION_MARKER))
                {
                    part = part.Replace(DELETION_MARKER, "");

                    string strippedPart = part.Replace(" ", "").Replace("\t", "");
                    if (strippedPart.Length == 0) continue;  //ie. don't include this line in the template
                }

                stringBuilder.Append(part);
                if (stringNum < stringParts.Length-1)
                {
                    stringBuilder.Append(Environment.NewLine);  // don't want to add a newline on the last item
                }
            }

            return stringBuilder.ToString();
        }
    }
}